package org.java.mathgame;


import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.InputListener;
import com.badlogic.gdx.scenes.scene2d.ui.Table;
import com.badlogic.gdx.scenes.scene2d.ui.TextButton;
import com.esotericsoftware.tablelayout.Cell;
import org.java.mathgame.screens.GameScreen;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.Scanner;

public class Grid extends Table {

    private GameScreen gameScreen;
    private int gridSize;
    private ArrayList<GridButton> selectedButtons;
    private ArrayList<GridButton> buttonList;
    private Random random;
    private float result;
    private int comboTime;
    private int lastTime;
    private int previousTime;
    private int corrAnswerCounter;
    private int timeDiff;
    private boolean flag = true;
    final int GAME_TIME = 60;
    private int scoreMulti = 10;
    private int multiChecker = 10;


    public Grid(GameScreen gameScreen, int gridSize, float cellSize, TextButton.TextButtonStyle gridButtonStyle, TextButton.TextButtonStyle operatorButtonStyle) {
        super();
        this.gameScreen = gameScreen;
        random = new Random();
        this.gridSize = gridSize;
        buttonList = new ArrayList<GridButton>();

        for (int i = 0; i < gridSize; i++) {
            for (int j = 0; j < gridSize - 1; j++) {
                GridButton button;
                String tempS = "";
                float tempF = 0f;
                if ((i == 0 && j == 0) || (i == 0 && j == 1))
                    tempS = "+";
                else if ((i == 0 && j == gridSize - 3) || (i == 0 && j == gridSize - 2))
                    tempS = "-";
                else if (((i == gridSize - 1 && j == 0) || (i == gridSize - 1 && j == 1)) && gameScreen.getGame().getDifficulty() > 1)
                    tempS = "*";
                else if (((i == gridSize - 1 && j == gridSize - 3) || (i == gridSize - 1 && j == gridSize - 2)) && gameScreen.getGame().getDifficulty() > 1)
                    tempS = "/";
                else
                    tempF = getNewFloat();
                if (tempF != 0f)
                    button = new GridButton(tempF, gridButtonStyle, i, j, tempF);
                else
                    button = new GridButton(tempS, gridButtonStyle, i, j, tempS);
                button.setName(i + "," + j);
                button.addListener(new InputListener() {
                    public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
                        return true;
                    }

                    public void touchUp(InputEvent event, float x, float y, int pointer, int button) {
                        Actor sender = event.getListenerActor();
                        //gameScreen.setOutput("button (" + sender.getName() + ") up", "clear");
                        GridButton pressedButton = (GridButton) sender;
                        pressedButton.setChecked(true);
                        Update(pressedButton);
                        //goalButton.setText(Integer.toString(grid.getResult()));
                    }
                });
                if (button.isNumber()) {
                    button.setStyle(operatorButtonStyle);

                }
                int cellWidth = Gdx.graphics.getWidth() / 4;
                if ((!button.isNumber()) && (j > 0) && (buttonList.get(i * 4 + j - 1).getOperator().equals(button.getOperator()))) {
                    List<Cell> cells = getCells();
                    Cell cell = cells.get(cells.size() - 1);
                    cell.width(2 * cell.getPrefWidth() + 5).colspan(2).space(5);//.width(2 * Gdx.graphics.getWidth() / gridSize);
                    cell.align(1);
                } else {
                    add(button).width(cellWidth - 7.5f).height(cellWidth - 7.5f).space(5);
                }
                this.pad(5);
                //debug();
                buttonList.add(button);
            }
            row();
        }
        selectedButtons = new ArrayList<GridButton>();
        result = getNewResult();
    }

    public ArrayList<GridButton> getButtonList() {
        return buttonList;
    }

    public float getResult() {
        return result;
    }

    public String getResultString() {
        return String.format("%.0f", result);
    }

    public float getNewFloat() {
        float rand;
        if (gameScreen.getGame().getDifficulty() == 1)
            rand = random.nextInt(10) + 1f;
        else if (gameScreen.getGame().getDifficulty() == 2)
            rand = random.nextInt(15) + 1f;
        else if (gameScreen.getGame().getDifficulty() == 3)
            rand = random.nextInt(15) + 1f;
        else
            rand = random.nextInt(30) + 1f;
        if (gameScreen.getGame().isNegative() && random.nextInt(2) == 0)
            rand *= -1f;
        return rand;
    }

    // TODO
    // can still use same operator twice
    public float getNewResult() {
        float result = -0.1f;
        while (result != Math.ceil(result) || (!gameScreen.getGame().isNegative() && result < 0)) {
            ArrayList<GridButton> chosenButtons = new ArrayList<GridButton>();
            int rand = random.nextInt(buttonList.size());
            while (!buttonList.get(rand).isNumber() || chosenButtons.contains(buttonList.get(rand)))
                rand = random.nextInt(buttonList.size());
            chosenButtons.add(buttonList.get(rand));
            while (buttonList.get(rand).isNumber())
                rand = random.nextInt(buttonList.size());
            chosenButtons.add(buttonList.get(rand));
            while (!buttonList.get(rand).isNumber() || chosenButtons.contains(buttonList.get(rand)))
                rand = random.nextInt(buttonList.size());
            chosenButtons.add(buttonList.get(rand));
            if (gameScreen.getGame().getDifficulty() > 2) {
                while (buttonList.get(rand).isNumber() || chosenButtons.get(1).getOperator().equalsIgnoreCase(buttonList.get(rand).getOperator()))
                    rand = random.nextInt(buttonList.size());
                chosenButtons.add(buttonList.get(rand));
                while (!buttonList.get(rand).isNumber() || chosenButtons.contains(buttonList.get(rand)))
                    rand = random.nextInt(buttonList.size());
                chosenButtons.add(buttonList.get(rand));
            }
            result = calculate(chosenButtons.toArray(new GridButton[chosenButtons.size()]));
        }
        return result;
    }

    public float calculate(GridButton... b) {
        if (b.length < 3 && b.length % 2 == 0 && !b[0].isNumber()) {
            System.out.println("panic");
            return 0f;
        }
        // debugging start
        for (GridButton button : b) {
            if (button.isNumber())
                System.out.print(button.getNumber());
            else
                System.out.print(button.getOperator());
        }
        System.out.println();
        // debugging end
        float result = b[0].getNumber();
        String temp = "0";
        for (GridButton input : b) {
            if (!input.isNumber()) {
                temp = input.getOperator();
            } else {
                if (temp.equalsIgnoreCase("+")) {
                    result += input.getNumber();
                } else if (temp.equalsIgnoreCase("-")) {
                    result -= input.getNumber();
                } else if (temp.equalsIgnoreCase("*")) {
                    result *= input.getNumber();
                } else if (temp.equalsIgnoreCase("/")) {
                    result /= input.getNumber();
                }
            }
        }
        return result;
    }

    public void refresh() {
        clear();
        gameScreen.setEquation("", "clear");
    }

    public void clear() {
        for (TextButton button : selectedButtons) {
            button.setChecked(false);
        }
        selectedButtons.clear();
        //gameScreen.setEquation("", "clear");
        /*for (Actor actor:GameScreen.table.getChildren()){
            TextButton button = (TextButton) actor;
            button.setChecked(false);
        }*/
    }

    public void scoreCalculator4GameModeOne() {
        previousTime = lastTime;
        lastTime = gameScreen.getGameTime();

        if ((corrAnswerCounter == 0) && (flag = true)) {
            flag = false;
            timeDiff = GAME_TIME - gameScreen.getGameTime();
            if (timeDiff <= 3) {
                gameScreen.score = 52;
                comboTime = timeDiff;
            } else if (timeDiff <= 7) {
                gameScreen.score += 34;
                comboTime = timeDiff;
            } else {
                gameScreen.score += 16;
                comboTime = timeDiff;
            }
        }
        if ((corrAnswerCounter == 0) && (flag = false)) {
            if ((timeDiff = previousTime - lastTime) <= 3) {
                gameScreen.score += 52;
                comboTime = timeDiff;
            } else if ((timeDiff = previousTime - lastTime) <= 7) {
                gameScreen.score += 34;
                comboTime = timeDiff;
            } else {
                gameScreen.score += 16;
                comboTime = timeDiff;
            }
        }
        if (corrAnswerCounter != 0 && corrAnswerCounter != 2) {
            if ((timeDiff = previousTime - lastTime) <= 3) {
                gameScreen.score += 52;
                comboTime += timeDiff;
            } else if ((timeDiff = previousTime - lastTime) <= 7) {
                gameScreen.score += 34;
                comboTime += timeDiff;
            } else {
                gameScreen.score += 16;
                comboTime += timeDiff;
            }

        }
        if (corrAnswerCounter == 2) {
            corrAnswerCounter = -1;
            if (comboTime <= 9) {
                gameScreen.score += 152;
                System.out.println("Triple combo x3");
            } else if (comboTime <= 21) {
                gameScreen.score += 94;
                System.out.println("Double combo x2");
            } else {
                gameScreen.score += 36;
                System.out.println("No combo occurred!");
            }
            comboTime = 0;
        }
        System.out.println(corrAnswerCounter + " " + gameScreen.score);
        corrAnswerCounter++;
    }

    public void scoreCalculator4GameModeTwo() {
        /*if (gameScreen.getGameTime() > multiChecker) {
            if (scoreMulti > 2) {
                scoreMulti--;
            }
            multiChecker += 10;
        }
        scoreMulti++;
        gameScreen.score = 20 * scoreMulti;
        gameScreen.score += 14;*/
        if (gameScreen.getGameTime() < 3)
            gameScreen.score += 526;
        else
            gameScreen.score += 526/(gameScreen.getGameTime()/3);
        gameScreen.score += 24;
    }


    public void Update(GridButton pressedButton) {
        if (selectedButtons.contains(pressedButton)) {
            gameScreen.setOutput("already selected", "clear");
            pressedButton.setChecked(true);
            return;
        }
        int last = 0;
        last = (gameScreen.getGame().getDifficulty() < 3) ? 3 : 5;
        Scanner s = new Scanner(pressedButton.getName().toString()).useDelimiter("\\D+");
        int i = s.nextInt();
        int j = s.nextInt();
        if (selectedButtons.size() < last) {
            if (selectedButtons.size() == 0) {
                gameScreen.setEquation("", "clear");
                gameScreen.infoEquationStyle.fontColor = Color.WHITE;
            }
            if (selectedButtons.size() % 2 == 0) {
                if (pressedButton.isNumber()) {
                    selectedButtons.add(pressedButton);
                    if (pressedButton.isNumber())
                        gameScreen.setEquation(String.format("%.0f", (Float) pressedButton.getNumber()), "add");
                    else
                        gameScreen.setEquation(pressedButton.getOperator(), "add");
                } else {
                    gameScreen.flashGrid("number");
                    pressedButton.setChecked(false);
                }
            } else {
                if (!pressedButton.isNumber()) {
                    selectedButtons.add(pressedButton);
                    if (pressedButton.isNumber())
                        gameScreen.setEquation(String.format("%.0f", (Float) pressedButton.getNumber()), "add");
                    else
                        gameScreen.setEquation(pressedButton.getOperator(), "add");
                } else {
                    gameScreen.flashGrid("operator");
                    pressedButton.setChecked(false);
                }
            }
        }
        if (selectedButtons.size() == last) {
            if (calculate(selectedButtons.toArray(new GridButton[selectedButtons.size()])) == result) {
                gameScreen.setOutput("correct", "clear");
                if (gameScreen.getGame().getGameMode() == 1) {
                    scoreCalculator4GameModeOne();
                } else {
                    scoreCalculator4GameModeTwo();
                }
                gameScreen.infoEquationStyle.fontColor = Color.GREEN;
                if (gameScreen.getGame().getGameMode() == 1)
                    gameScreen.setScore(gameScreen.getScore());
                else if (gameScreen.getGame().getGameMode() == 2) {
                    gameScreen.setScore(gameScreen.getScore());
                }
                for (GridButton button : selectedButtons) {
                    if (button.isNumber()) {
                        if (gameScreen.getGame().getGameMode() == 1) {
                            button.setValue(getNewFloat());
                            button.setText(String.format("%.0f", button.getNumber()));
                        } else if (gameScreen.getGame().getGameMode() == 2) {
                            buttonList.remove(button);
                            button.remove();
                        }
                    }
                }
                clear();
                for (GridButton buttonsAll : buttonList) {
                    if (buttonsAll.isNumber()) {
                        result = getNewResult();
                        clear();
                        return;
                    }
                }
                gameScreen.setGameOver(true);
                gameScreen.onGameOver();
                gameScreen.getGame().setGameRunning(false);
            } else {
                clear();
                gameScreen.setOutput("incorrect", "clear");
                gameScreen.infoEquationStyle.fontColor = Color.RED;
            }
            clear();
        }
    }
}
